/**
 * Created by Richard Radlherr.
 * Date: 09.07.2006 18:42
 */

using System;
using System.Collections.Generic;
using CsGL.OpenGL;

namespace TagTool.GraphicTypes
{
	
	/**
	 * A Tag is a simple drawing of lines with its own transfromations
	 * The Tag controls its own glList.
	 */
	[Serializable()]
	public class TexturedTag : Shape, IDisposable
	{
		private List< List <TexturedPoint> > lines = new List< List <TexturedPoint> >();
		private List <TexturedPoint> line = null;
		
		private List<uint> glLines = new List<uint>();
		private uint glLine = 0;

		private Texture texture = new Texture();

		public TexturedTag()
		{
		}
		
		public Texture Texture
		{
			get { return texture; }
			set { texture = value; }
		}
		
		public override void Dispose()
		{
			if (line != null)
			{
				line.Clear();
			}
			base.Dispose();
		}
		
		public void AddPoint(TexturedPoint point)
		{
			if (line == null)
			{
				AddLine();
			}
			line.Add(point);
			
			if (x1 > point.X)
			{
				x1 = point.X;
			}
			if (x2 < point.X)
			{
				x2 = point.X;
			}
			
			if (y1 > point.Y)
			{
				y1 = point.Y;
			}
			if (y2 < point.Y)
			{
				y2 = point.Y;
			}
			
			if (line != null && lines.Count > 0)
			{
				glNewList(glLines[lines.Count - 1], GL_COMPILE);
				DrawLine(lines[lines.Count - 1]);
				glEndList();
			}
			Update();
		}
		
		public override void SetPivot()
		{
			double mx = (x2 - x1) / 2;
			double my = (y2 - y1) / 2;
			uint gl;
			int i = 0;
			foreach (List <TexturedPoint> line in lines)
			{
				gl = glLines[i];
				
				foreach (TexturedPoint point in line)
				{
					point.Add(mx, -my, 0);
				}
				
				glNewList(gl, GL_COMPILE);
				DrawLine(line);
				glEndList();
				
				i++;
			}
			

		}
		
		public void AddLine()
		{
			
			if (line != null)
			{
				glNewList(glLine, GL_COMPILE);
				if (lines.Count > 0)
				{
					DrawLine(lines[lines.Count - 1]);
				}
				glEndList();
				
			}
			
			Update();
			
			line = new List<TexturedPoint>(2048);
			lines.Add(line);
			
			glLine = glGenLists(1);
			glNewList(glLine, GL_COMPILE);
			glEndList();
			
			glLines.Add(glLine);
		}
		
		public void Clear()
		{
			
			foreach (uint i in glLines )
			{
				glDeleteLists(i, 1);
			}
			glLines.Clear();
			lines.Clear();
			
			Update();
		}
		
		private void DrawLine(List<TexturedPoint> line)
		{
			
			if (texture != null)
			{
				glEnable(GL_TEXTURE_2D);
				texture.Apply();
				uint i =  glGetError();
			}
			
			CsGL.OpenGL.GL.glBegin(CsGL.OpenGL.GL.GL_TRIANGLE_STRIP);
			
			if (line.Count > 1)
			{
				List<TexturedPoint>.Enumerator curPoint = line.GetEnumerator();
				PointD a = new PointD();
				PointD b = new PointD();
				
				bool first = true;
				PointD start = line[0];
				PointD dir;
				bool toggle = false;
				double d, l = 0;
				
				double c = 0;
				
				while(curPoint.MoveNext())
				{
					if (first)
					{
						first = false;
						a = b = curPoint.Current;
					}
					else
					{
						dir = curPoint.Current - start;
						d = dir.X;
						dir.X = -dir.Y;
						dir.Y = d;
						dir = dir.Normalize();
						l = dir.Length;
						if (Math.Abs(l) > 0.05)
						{
							a = curPoint.Current + dir * curPoint.Current.Width;
							b = curPoint.Current - dir * curPoint.Current.Width;
							start = curPoint.Current;
						}
						else
						{
							continue;
						}
					}
		
					CsGL.OpenGL.GL.glColor4d( curPoint.Current.Color.R, curPoint.Current.Color.G, curPoint.Current.Color.B, curPoint.Current.Color.A);
					
					if (texture != null)
					{
						glTexCoord2d(0.0, c / texture.Height);
					}
					
					CsGL.OpenGL.GL.glVertex3d(a.X, a.Y, a.Z);
					
					if (texture != null)
					{
						glTexCoord2d(1.0, c / texture.Height);
					}
					CsGL.OpenGL.GL.glVertex3d(b.X, b.Y, b.Z);
					
					toggle = !toggle;
					
					c += l;
				}
				
			}
			
			CsGL.OpenGL.GL.glEnd();
			
			glDisable(GL_TEXTURE_2D);
		}

		protected override void Compile()
		{
			foreach(uint line in glLines)
			{
				glCallList(line);
				glFlush();
			}
		}
		
	}
	
}
